package com.zeyu.framework.tools.schedule.job;

import com.zeyu.framework.tools.schedule.entity.JobEntity;
import com.zeyu.framework.tools.schedule.entity.ScheduleHistory;
import com.zeyu.framework.tools.schedule.service.ScheduleHistoryService;
import com.zeyu.framework.utils.SpringContextHolder;
import com.zeyu.framework.utils.ThreadUtils;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Job的基本对象,进行了对象的转化和封装,系统的quartz任务需要继承
 * Created by zeyuphoenix on 16/6/20.
 */
public abstract class AbstractJob implements Job {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    // ================================================================
    // Fields
    // ================================================================

    // quartz 任务
    protected JobDetail jobDetail;
    // quartz 触发器
    protected Trigger trigger;
    // quartz 数据
    protected JobDataMap jobDataMap;
    // 自定义任务数据对象, database <--> web display
    // 可以通过 JobService 获取,为了性能,这里暂时不获取.
    protected JobEntity jobEntity;

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 任务计时
        long begin = System.currentTimeMillis();
        ScheduleHistory scheduleHistory = new ScheduleHistory();
        try {
            // get date
            this.jobDetail = context.getJobDetail();
            this.trigger = context.getTrigger();
            this.jobDataMap = this.jobDetail.getJobDataMap();
            // 为了性能, 只获取基本entity
            //Just log .
            if (jobEntity == null) {
                jobEntity = new JobEntity(jobDetail.getKey().getName(),
                        jobDetail.getKey().getGroup());
                jobEntity.setDescription(jobDetail.getDescription());
            }
            JobEntity.JobRuntimeEntity runtimeEntity = jobEntity.getJobRuntimeEntity();
            if (runtimeEntity == null) {
                runtimeEntity = new JobEntity.JobRuntimeEntity();
            }
            runtimeEntity.setFireCount(context.getRefireCount());
            runtimeEntity.setFireTime(context.getFireTime());
            runtimeEntity.setScheduledFireTime(context.getScheduledFireTime());
            runtimeEntity.setPreviousFireTime(context.getPreviousFireTime());
            runtimeEntity.setNextFireTime(context.getNextFireTime());
            this.jobEntity.setJobRuntimeEntity(runtimeEntity);
            this.jobDataMap.put(JobEntity.ENTITY_KEY, jobEntity);

            // 执行
            this.process();

            long end = System.currentTimeMillis();

            if (logger.isDebugEnabled()) {
                logger.debug("complete job -> name : {}, group: {}, time : {}", jobDetail.getKey().getName(),
                        jobDetail.getKey().getGroup(), (end - begin));
            }
        } catch (Exception e) {
            logger.error(String.format("error job -> name : %s, group: %s.", jobDetail.getKey().getName(),
                    jobDetail.getKey().getGroup()), e);
            scheduleHistory.setStatus(1);
        }

        // 可以记录历史记录
        if (jobDetail.getJobDataMap().getBoolean("history")) {

            ThreadUtils.addExecuteTask(() -> {

                // 构造任务执行结果
                scheduleHistory.setDuration((int) (System.currentTimeMillis() - begin));
                scheduleHistory.setFinishTime(new Date());
                scheduleHistory.setStartTime(new Date(begin));
                scheduleHistory.setDescription(this.jobEntity.getDescription());

                scheduleHistory.setGroup(this.jobEntity.getGroup());
                scheduleHistory.setName(this.jobEntity.getName());
                setCron(scheduleHistory);

                // 获取schedule history bean
                ScheduleHistoryService scheduleHistoryService = SpringContextHolder.getBean(ScheduleHistoryService.class);
                if (scheduleHistoryService != null)
                    scheduleHistoryService.save(scheduleHistory);

                logger.debug("schedule history is {}", scheduleHistory);
            });
        }
    }

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 执行处理任务,子类实现
     */
    public abstract void process() throws Exception;

    // ================================================================
    // Getter & Setter
    // ================================================================

    public JobDetail getJobDetail() {
        return jobDetail;
    }

    public void setJobDetail(JobDetail jobDetail) {
        this.jobDetail = jobDetail;
    }

    public Trigger getTrigger() {
        return trigger;
    }

    public void setTrigger(Trigger trigger) {
        this.trigger = trigger;
    }

    public JobDataMap getJobDataMap() {
        return jobDataMap;
    }

    public void setJobDataMap(JobDataMap jobDataMap) {
        this.jobDataMap = jobDataMap;
    }

    public JobEntity getJobEntity() {
        return jobEntity;
    }

    public void setJobEntity(JobEntity jobEntity) {
        this.jobEntity = jobEntity;
    }

    // ================================================================
    // Private Methods
    // ================================================================

    /**
     * 设置执行历史的时间
     */
    private void setCron(ScheduleHistory scheduleHistory) {
        if (trigger instanceof SimpleTrigger) {
            SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
            TimeUnit unit = TimeUnit.SECONDS;

            scheduleHistory.setType(0);
            scheduleHistory.setCron((int) unit.convert(simpleTrigger.getRepeatInterval(),
                    TimeUnit.MILLISECONDS) + "/" + unit.name());
        } else if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;

            scheduleHistory.setType(1);
            scheduleHistory.setCron(cronTrigger.getCronExpression());
        }

    }

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================

}
